package vn.axonactive.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

import vn.axonactive.Product;

/**
 * @author nhan.nguyen
 */
public class ProductFactory {

	private static ProductFactory instance = new ProductFactory();
	private static final String FAKE_PRODUCT_EXCEL = "fake_product.xls";
	private static final String REPOSITORY_DATA_PATH = "D://fake_product.xls";

	private ProductFactory() {

	}

	public static ProductFactory getInstance() {
		return instance;
	}

	/**
	 * Provide a list of fake {@link Product} by reading data from
	 * /src/main/java/vn/axonactive/rest/fake_product.xls file.
	 * 
	 * @return {@link List} of {@link Product}.
	 * @throws IOException
	 *             if fail to read fake data from
	 *             /src/main/java/vn/axonactive/rest/fake_product.xls file.
	 */
	public List<Product> feedData() throws IOException {
		List<Product> productList = new ArrayList<Product>();
		/*
		 * InputStream inputStream = getClass().getResourceAsStream(
		 * FAKE_PRODUCT_EXCEL);
		 */
		initiateRepositoryData();
		InputStream inputStream = new FileInputStream(REPOSITORY_DATA_PATH);
		HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
		HSSFSheet sheet = workbook.getSheetAt(0);

		Iterator<Row> rows = sheet.iterator();
		// skip the header row
		rows.next();

		while (rows.hasNext()) {
			Row row = rows.next();
			// get data from cells
			String code = row.getCell(0).getStringCellValue();
			String title = row.getCell(1).getStringCellValue();
			String description = row.getCell(2).getStringCellValue();
			double price = (double) row.getCell(3).getNumericCellValue();
			long rank = (long) row.getCell(4).getNumericCellValue();
			long amount = (long) row.getCell(5).getNumericCellValue();
			
			String imageURL = row.getCell(6).getStringCellValue();
			// parse data into product object
			Product product = new Product();
			product.setCode(code);
			product.setTitle(title);
			product.setDescription(description);
			product.setPrice(price);
			product.setRank(rank);
			product.setAmount(amount);
			product.setImageURL(imageURL);
			productList.add(product);
		}
		// close the stream
		inputStream.close();

		return productList;

	}

	/**
	 * Provide a list of product based on title and ranking
	 * 
	 * 
	 * @return {@link List} of {@link Product}.
	 * 
	 */
	public List<Product> searchProduct(String title, long rank) {
		List<Product> productList = new ArrayList<Product>();
		try {
			productList = feedData();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		if (title == null) {
			title = "";
		}
		title = title.toLowerCase();
		List<Product> filteredProducts = new ArrayList<Product>();

		for (Product product : productList) {
			String pTitle = product.getTitle().toLowerCase();
			long pRank = product.getRank();
			boolean isMatch = (rank > 0 && rank == pRank && pTitle
					.contains(title))
					|| (rank == 0 && pTitle.contains(title));

			if (isMatch)
				filteredProducts.add(product);
		}
		return filteredProducts;

	}

	/**
	 * Get a product based on code
	 * 
	 * 
	 * @return {@link Product}.
	 * 
	 */
	public Product getProductByCode(String code) {
		List<Product> productList = new ArrayList<Product>();
		try {
			productList = feedData();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		for (Product product : productList) {
			if (code.equals(product.getCode()))
				return product;
		}

		return null;
	}

	/**
	 * Create a new product
	 */

	public void createProduct(Product product) throws IOException {
		initiateRepositoryData();
		InputStream inputStream = new FileInputStream(REPOSITORY_DATA_PATH);
		HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
		HSSFSheet sheet = workbook.getSheetAt(0);
		Row row = sheet.createRow(sheet.getLastRowNum() + 1);
		// Create code cell
		Cell codeCell = row.createCell(0);
		codeCell.setCellValue((String) product.getCode());
		// Create title cell
		Cell titleCell = row.createCell(1);
		titleCell.setCellValue((String) product.getTitle());
		// Create description cell
		Cell desCell = row.createCell(2);
		desCell.setCellValue((String) product.getDescription());
		// Create price cell
		Cell priceCell = row.createCell(3);
		priceCell.setCellValue((double) product.getPrice());
		// Create rank cell
		Cell rankCell = row.createCell(4);
		rankCell.setCellValue((long) product.getRank());
		
		// Create amount cell
		Cell amountCell = row.createCell(5);
		amountCell.setCellValue((long) product.getAmount());
		
		// Create image URL cell
		Cell imageURLCell = row.createCell(6);
		imageURLCell.setCellValue( product.getImageURL());
		

		/*
		 * URL resourceUrl = getClass().getResource(FAKE_PRODUCT_EXCEL); File
		 * file=null; try { file = new File(resourceUrl.toURI()); } catch
		 * (URISyntaxException e) { // TODO Auto-generated catch block
		 * e.printStackTrace(); }
		 */
		OutputStream output = new FileOutputStream(REPOSITORY_DATA_PATH);

		workbook.write(output);
		output.flush();
		output.close();

		// close the stream
		inputStream.close();

	}

	/**
	 * Create/update a new product
	 */

	public void createUpdateProduct(Product product) throws IOException {
		boolean isExisting = false;
		initiateRepositoryData();
		InputStream inputStream = new FileInputStream(REPOSITORY_DATA_PATH);
		HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
		HSSFSheet sheet = workbook.getSheetAt(0);

		Iterator<Row> rows = sheet.iterator();
		// skip the header row
		rows.next();

		while (rows.hasNext()) {
			Row row = rows.next();
			// get data from cells
			String code = row.getCell(0).getStringCellValue();
			// Check code to update
			if (code.equals(product.getCode())) {
				row.getCell(1).setCellValue(product.getTitle());
				isExisting = true;
				break;

			}
		}

		// update
		if (isExisting) {

			OutputStream output = new FileOutputStream(REPOSITORY_DATA_PATH);
			workbook.write(output);
			output.flush();
			output.close();
			// close the stream
			inputStream.close();

		}
		// create
		else {
			createProduct(product);

		}

	}

	/**
	 * Remove a a product based on code
	 */

	public void removeProduct(String code) throws IOException {

		initiateRepositoryData();
		InputStream inputStream = new FileInputStream(REPOSITORY_DATA_PATH);
		HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
		HSSFSheet sheet = workbook.getSheetAt(0);

		Iterator<Row> rows = sheet.iterator();
		// skip the header row
		rows.next();

		while (rows.hasNext()) {
			Row row = rows.next();
			// get data from cells
			String codeCell = row.getCell(0).getStringCellValue();
			// Check code to update
			if (codeCell.equals(code)) {
				sheet.removeRow(row);
				break;

			}
		}
		OutputStream output = new FileOutputStream(REPOSITORY_DATA_PATH);
		workbook.write(output);
		output.flush();
		output.close();
		// close the stream
		inputStream.close();

	}

	/**
	 * Initiate REPOSITORY DATA based on Fake data of project
	 */

	private void initiateRepositoryData() {
		File file = new File(REPOSITORY_DATA_PATH);
		if (file.exists())
			return;

		// copy fakeData to repository

		OutputStream outputStream = null;
		InputStream inputStream = getClass().getResourceAsStream(
				FAKE_PRODUCT_EXCEL);
		// write the inputStream to a FileOutputStream
		try {
			outputStream = new FileOutputStream(file);

			int read = 0;
			byte[] bytes = new byte[1024];

			while ((read = inputStream.read(bytes)) != -1) {
				outputStream.write(bytes, 0, read);
			}

			System.out.println("Done!");

		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (outputStream != null) {
				try {
					// outputStream.flush();
					outputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}

			}
		}
	}

}
